package src.Players;

import src.Util.*;
import src.Main;
import src.NPCs.*;

public class PlayerUpdate
{
    public PlayerUpdate()
    {
    }

    public void updatePlayer(Player p, Stream str)
    {
        if(p == null || str == null)
        {
            return;
        }
        Main.m.ge.globalStream.resetOffset();
        Main.m.ge.moveP.updateThisPlayerMovement(p, str);
        boolean saveChatTextUpdate = p.chatTextUpdateRequired;
        p.chatTextUpdateRequired = false;
        appendPlayerUpdateBlock(p, Main.m.ge.globalStream);
        p.chatTextUpdateRequired = saveChatTextUpdate;
        str.writeBits(8, p.playerListSize);
        int size = p.playerListSize;
        p.playerListSize = 0;
        for(int i = 0; i < size; i++)
        {
            if(p.playerList[i] == null || !p.playerList[i].isOnline)
            {
                continue;
            }
            if(!p.playerList[i].didTeleport && withinDistance(p, p.playerList[i]))
            {
                Main.m.ge.moveP.updatePlayerMovement(p.playerList[i], str);
                appendPlayerUpdateBlock(p.playerList[i], Main.m.ge.globalStream);
                p.playerList[p.playerListSize++] = p.playerList[i];
            }
            else
            {
                int id = p.playerList[i].playerIndex;
                p.playerInListBitmap[id >> 3] &= ~(1 << (id & 7));
                str.writeBits(1, 1);
                str.writeBits(2, 3);
            }
        }
        for(Player pl : Main.m.ge.players)
        {
            if(pl == null || pl == p || !pl.isOnline)
            {
                continue;
            }
            int id = pl.playerIndex;
            if((p.playerInListBitmap[id >> 3] & (1 << (id & 7))) != 0 || !withinDistance(p, pl))
            {
                continue;
            }
            addNewPlayer(p, pl, str);
        }
        if(Main.m.ge.globalStream.getOffset() > 0)
        {
            str.writeBits(11, 2047);
            str.finishBitAccess();
            str.writeBytes(Main.m.ge.globalStream.getBuffer(), Main.m.ge.globalStream.getOffset(), 0);
        }
        else
        {
            str.finishBitAccess();
        }
        str.endFrameVarSizeWord();
    }

    public void appendPlayerUpdateBlock(Player p, Stream str)
    {
        if(p == null || str == null)
        {
            return;
        }
        if(!p.updateRequired && !p.chatTextUpdateRequired)
        {
            return;
        }
        PlayerUpdateBlock ub = new PlayerUpdateBlock();
        int updateMask = 0;
        if(p.mask400)
        {
            updateMask |= 0x400;
        }
        if(p.gfxUpdateRequired)
        {
            updateMask |= 0x100;
        }
        if(p.animUpdateRequired)
        {
            updateMask |= 8;
        }
        if(p.chatTextUpdateRequired)
        {
            updateMask |= 0x80;
        }
        if(p.faceToUpdateRequired)
        {
            updateMask |= 1;
        }
        if(p.appearanceUpdateRequired)
        {
            updateMask |= 0x10;
        }
        if(p.hit1UpdateRequired)
        {
            updateMask |= 0x20;
        }
        ub.writeMask(str, updateMask);
        if(p.mask400)
        {
            ub.appendMask400(p, str);
        }
        if(p.gfxUpdateRequired)
        {
            ub.appendGraphicsRequest(p, str);
        }
        if(p.animUpdateRequired)
        {
            ub.appendAnimationRequest(p, str);
        }
        if(p.chatTextUpdateRequired)
        {
            ub.appendPlayerChatText(p, str);
        }
        if(p.faceToUpdateRequired)
        {
            ub.appendFaceTo(p, str);
        }
        if(p.appearanceUpdateRequired)
        {
            ub.appendPlayerAppearance(p, str);
        }
        if(p.hit1UpdateRequired)
        {
            ub.appendHit1(p, str);
        }
        ub = null;
    }

    private boolean withinDistance(Player p, Player otherPlr)
    {
        if(otherPlr != null && p != null)
        {
            if(p.heightLevel != otherPlr.heightLevel)
            {
                return false;
            }
            int deltaX = otherPlr.absX - p.absX, deltaY = otherPlr.absY - p.absY;
            return (deltaX <= 15 && deltaX >= -16 && deltaY <= 15 && deltaY >= -16);
        }
        return false;
    }

    public void update(Player p)
    {
        updatePlayer(p, p.outStream);
        Main.m.ge.updateN.updateNPC(p, p.outStream);
    }

    public void clearUpdateFlags(Player p)
    {
        p.updateRequired = false;
        p.appearanceUpdateRequired = false;
        p.chatTextUpdateRequired = false;
        p.animUpdateRequired = false;
        p.gfxUpdateRequired = false;
        p.faceToUpdateRequired = false;
        p.hit1UpdateRequired = false;
        p.mask400 = false;
        p.animRequest = 65535;
        p.animDelay = 0;
        p.gfxRequest = 65535;
        p.gfxDelay = 0;
        p.hitDiff1 = 0;
        p.posionHit1 = 0;
    }

    public void addNewPlayer(Player p, Player plr, Stream str)
    {
        if(p == null || str == null)
        {
            return;
        }
        if(plr != null)
        {
            int id = plr.playerIndex;
            p.playerInListBitmap[id >> 3] |= 1 << (id&7);
            p.playerList[p.playerListSize++] = plr;
            str.writeBits(11, id);
            str.writeBits(1, 1);
            boolean savedFlag = plr.appearanceUpdateRequired;
            boolean savedUpdateRequired = plr.updateRequired;
            plr.appearanceUpdateRequired = true;
            plr.updateRequired = true;
            appendPlayerUpdateBlock(plr, Main.m.ge.globalStream);
            plr.appearanceUpdateRequired = savedFlag;
            plr.updateRequired = savedUpdateRequired;
            str.writeBits(1, 1);
            int z = plr.absY - p.absY;
            if(z < 0)
                z += 32;
            str.writeBits(5, z);
            z = plr.absX - p.absX;
            if(z < 0)
                z += 32;
            str.writeBits(5, z);
        }
    }
}